#pragma once
#include<jsoncpp/json/json.h>
#include "compile.hpp"
#include "run.hpp"

enum Status_Code{
    SUCESS = 0,
    COMPILE_ERROR = -1,//编译错误
    RUN_ERROR = -2,//运行过程中的服务器内部错误
    INTERNAL_ERROR = -3,//内部错误
    CODE_EMPTY = -4,//代码为空

};

class CompileToRun {
    public:
        static void RemoveTempFiles(const std::string &filename)
        {
            std::string src_file = Util_File::ExtensionSrc(filename);
            if(Util_File::IsFileExist(src_file))
                unlink(src_file.c_str());

            std::string obj_file = Util_File::ExtensionObj(filename);
            if(Util_File::IsFileExist(obj_file))
                unlink(obj_file.c_str());
            
            std::string comp_error_file = Util_File::ExtCompError(filename);
            if(Util_File::IsFileExist(comp_error_file))
                unlink(comp_error_file.c_str());
            
            std::string stdin_file = Util_File::Stdindup(filename);
            if(Util_File::IsFileExist(stdin_file))
                unlink(stdin_file.c_str());
            
            std::string stdout_file = Util_File::Stdoutdup(filename);
            if(Util_File::IsFileExist(stdout_file))
                unlink(stdout_file.c_str());
            
            std::string stderr_file = Util_File::Stderrdup(filename);
            if(Util_File::IsFileExist(stderr_file))
                unlink(stderr_file.c_str());
        }
        static std::string CodeToDesc(int status_code,const std::string &filename)
        {
            switch(status_code){
                case SUCESS:
                    return "运行成功";
                    break;
                case COMPILE_ERROR:{
                    std::string error_msg;
                    Util_File::ReadFile(Util_File::ExtCompError(filename), &error_msg);
                    return error_msg;
                    break;
                }
                   
                case RUN_ERROR:
                    return "运行过程中的服务器内部错误";
                    break;
                case INTERNAL_ERROR:
                    return "内部错误";
                    break;
                case CODE_EMPTY:
                    return "代码为空";
                    break;
                default:
                    return "未知错误";
                    break;
            }
        }

        //网络传输中用json格式传输数据（序列化和反序列化），这里的json格式是编译器的输入，运行器的输出
        /***********************************
         * 输入json格式：
         * {
         *     "code" : "#include..."  -> 用户提交的代码
         *     "input" : "..."        -> 用户给自己提交代码对应的输入
         *      "cpu_limit : ...       -> 题目要求的时间限制
         *      "mem_limit" : ...      -> 题目要求的空间限制
         * }
         * 
         * 输出json格式：
         * {
         *      "status" : 状态码
         *      "message" : 状态信息
         *      "stdout" : 程序运行完的结果
         *      "stderr" : 程序运行过程中出现的错误信息
         * }
         **********************************/

         //该函数是将客户通过网络传输的代码编译成可执行文件，并运行，并将运行结果返回给客户
        static void Start(const std::string &in_json ,std::string *out_json)
        {
            Json::Value json_in;
            Json::Reader reader;
            reader.parse(in_json, json_in);//反序列化

            std::string code = json_in["code"].asString();
            std::string input = json_in["input"].asString();
            int cpu_limit = json_in["cpu_limit"].asInt();
            int mem_limit = json_in["mem_limit"].asInt();
            
            Json::Value json_out;//序列化输出值
            std::string filename;//编译器生成的可执行文件名
            int status_code = 0;//状态码
            int run_status = 0;//代码运行结果状态
            //用户提交的代码为空
            if(code.empty()){
                status_code = CODE_EMPTY;
                goto END;
            }
            filename = Util_File::UniqueFileName();//生成唯一的文件名
            //在本地创建并写入文件失败
            if(!Util_File::WriteFile(Util_File::ExtensionSrc(filename), code)){
                status_code = INTERNAL_ERROR;
                goto END;
            }
            //编译失败
            if(!Compile_Modle::Compile(filename)){
                status_code = COMPILE_ERROR;
                goto END;
            }
            run_status = Run_Modle::Run(filename, cpu_limit, mem_limit);//运行代码
            if(run_status < 0){
                status_code = RUN_ERROR;
            }else if(run_status == 0){//运行成功
                status_code = SUCESS;
            }else{//运行过程中被信号中断
                status_code = run_status;
            }
        END:
            json_out["status"] = status_code;
            json_out["message"] = CodeToDesc(status_code,filename);
            if(status_code == SUCESS){//整个过程全部成功
                std::string stdout_str;
                std::string stderr_str;
                Util_File::ReadFile(Util_File::Stdoutdup(filename), &stdout_str);
                Util_File::ReadFile(Util_File::Stderrdup(filename), &stderr_str);
                json_out["stdout"] = stdout_str;
                json_out["stderr"] = stderr_str;
            }
            Json::StreamWriterBuilder writer;
            writer.settings_["indentation"] = "    ";
            writer.settings_["emitUTF8"] = true;

            *out_json = Json::writeString(writer, json_out);

            RemoveTempFiles(filename);//删除临时文件

        }
};

